﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using YJKGeometryFuncs;
using YJKGeometryFuncs.CurveUtility;
using YJKPatternSign.StairsRoomPlanSign.ModelLayer;

namespace YJKPatternSign.StairsRoomPlanSign
{
	public static class Utility
	{
		public static Line MoveALineAtVerticalDirection(Line input, double distance, bool ifAnotherDirection = false)
		{
			Transform transform = Transform.CreateTranslation(Utility.GetAVerticalVector(input.Direction, ifAnotherDirection).Multiply(distance));
			return input.CreateTransformed(transform) as Line;
		}

		public static List<Curve> ChangeLstCurveZ(List<Curve> input, double useZ)
		{
			List<Curve> list = new List<Curve>();
			foreach (Curve inputCurve in input)
			{
				list.Add(CurveUtility.TransformCurveAtZAixs(inputCurve, useZ, true));
			}
			return list;
		}

		public static XYZ CalculateDistanceVetcor(XYZ inputPoint, Curve inputCurve, out XYZ projectPoint)
		{
			inputCurve.Clone().MakeUnbound();
			projectPoint = inputCurve.Project(inputPoint).XYZPoint;
			return (projectPoint - inputPoint).Normalize();
		}

		public static Curve ChangeCurveZ(Curve input, double useZ)
		{
			return CurveUtility.TransformCurveAtZAixs(input, useZ, true);
		}

		public static List<Line> GetStairBound(Stairs stairsPar)
		{
			List<Line> list = new List<Line>();
			List<Curve> list2 = new List<Curve>();
			Document document = stairsPar.Document;
			List<ElementId> list3 = stairsPar.GetStairsRuns().ToList<ElementId>();
			List<ElementId> list4 = stairsPar.GetStairsLandings().ToList<ElementId>();
			foreach (ElementId elementId in list3)
			{
				StairsRun stairsRun = document.GetElement(elementId) as StairsRun;
				list2.AddRange(stairsRun.GetFootprintBoundary().ToList<Curve>());
			}
			foreach (ElementId elementId2 in list4)
			{
				StairsLanding stairsLanding = document.GetElement(elementId2) as StairsLanding;
				list2.AddRange(stairsLanding.GetFootprintBoundary().ToList<Curve>());
			}
			foreach (Curve curve in list2)
			{
				Line line = curve as Line;
				if (line != null)
				{
					list.Add(line);
				}
			}
			return list;
		}

		public static double GetShelterHeightOfTwoStairs(Stairs nowStairs, Stairs downStairs, double nowCutValue)
		{
			double actualRiserHeight = nowStairs.ActualRiserHeight;
			double actualTreadDepth = nowStairs.ActualTreadDepth;
			double actualRiserHeight2 = downStairs.ActualRiserHeight;
			double actualTreadDepth2 = downStairs.ActualTreadDepth;
			if (Geometry.IsEqual(actualRiserHeight, 0.0) || Geometry.IsEqual(actualTreadDepth, 0.0) || Geometry.IsEqual(actualRiserHeight2, 0.0) || Geometry.IsEqual(actualTreadDepth2, 0.0))
			{
				return -1.0;
			}
			int num = (int)((nowCutValue - nowStairs.BaseElevation) / actualRiserHeight);
			if (num < 0)
			{
				return -1.0;
			}
			int num2 = (int)((double)num * actualTreadDepth / actualTreadDepth2 + 0.5);
			return downStairs.BaseElevation + (double)num2 * actualRiserHeight2;
		}

		public static XYZ GetAFaceMidPoint(PlanarFace input)
		{
			XYZ xyz = XYZ.Zero;
			int num = 0;
			foreach (CurveLoop curveLoop in input.GetEdgesAsCurveLoops())
			{
				foreach (Curve curve in curveLoop)
				{
					xyz = xyz.Add(curve.GetEndPoint(0));
					xyz = xyz.Add(curve.GetEndPoint(1));
					num += 2;
				}
			}
			return xyz.Divide((double)num);
		}

		public static XYZ GetAnearPoint(Curve inputOne, Curve inputTwo)
		{
			int num = 0;
			int num2 = 1;
			XYZ xyzpoint = inputTwo.Project(inputOne.GetEndPoint(num)).XYZPoint;
			XYZ xyzpoint2 = inputTwo.Project(inputOne.GetEndPoint(num2)).XYZPoint;
			if (xyzpoint.DistanceTo(inputOne.GetEndPoint(num)) > xyzpoint2.DistanceTo(inputOne.GetEndPoint(num2)))
			{
				return inputOne.GetEndPoint(num2);
			}
			return inputOne.GetEndPoint(num);
		}

		public static XYZ GetAVerticalVector(XYZ input, bool ifChanege = false)
		{
			if (!ifChanege)
			{
				return new XYZ(-input.Y, input.X, input.Z).Normalize();
			}
			return new XYZ(input.Y, -input.X, input.Z).Normalize();
		}

		public static double PointToLineMindDistance(XYZ inputPoint, Line inputLine)
		{
			return Math.Min(inputPoint.DistanceTo(inputLine.GetEndPoint(0)), inputPoint.DistanceTo(inputLine.GetEndPoint(1)));
		}

		public static double DistanceForPointToPlanarFaceOrginPointAtSameZ(XYZ input, PlanarFace inputFace)
		{
			XYZ xyz = inputFace.Origin;
			xyz = new XYZ(xyz.X, xyz.Y, input.Z);
			return xyz.DistanceTo(input);
		}

		public static List<XYZ> GetEndPointList(Line inputLine)
		{
			return new List<XYZ>
			{
				inputLine.GetEndPoint(0),
				inputLine.GetEndPoint(1)
			};
		}

		public static Line OffestLineToUseZ(Line inputLine, double useZ)
		{
			XYZ endPoint = inputLine.GetEndPoint(0);
			XYZ endPoint2 = inputLine.GetEndPoint(1);
			return Line.CreateBound(new XYZ(endPoint.X, endPoint.Y, useZ), new XYZ(endPoint2.X, endPoint2.Y, useZ));
		}

		public static bool iFTwoWallIntersection(Wall wallOne, Wall wallTwo, double useZ)
		{
			if (wallOne.Id.IntegerValue == wallTwo.Id.IntegerValue)
			{
				return false;
			}
			Line line = Utility.OffestLineToUseZ((wallOne.Location as LocationCurve).Curve as Line, useZ);
			Line line2 = Utility.OffestLineToUseZ((wallTwo.Location as LocationCurve).Curve as Line, useZ);
			List<Line> list = new List<Line>();
			list.Add(line);
			list.Add(line.CreateOffset(wallOne.Width / 2.0, XYZ.BasisZ) as Line);
			list.Add(line.CreateOffset(wallOne.Width / 2.0, -XYZ.BasisZ) as Line);
			List<Line> list2 = new List<Line>();
			list2.Add(line2);
			list2.Add(line2.CreateOffset(wallTwo.Width / 2.0, XYZ.BasisZ) as Line);
			list2.Add(line2.CreateOffset(wallTwo.Width / 2.0, -XYZ.BasisZ) as Line);
			foreach (Line line3 in list)
			{
				foreach (Line line4 in list2)
				{
					SetComparisonResult setComparisonResult = line3.Intersect(line4);
					if (8 == (int)setComparisonResult)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static XYZ GetCurveMidPoint(Curve input)
		{
			return input.GetEndPoint(0).Add(input.GetEndPoint(1)).Divide(2.0);
		}

		public static XYZ GetCurveMidPointInBounding(Curve input, BoundingBoxPakcer boundingBoxPacker, double useZ, out Curve useOutCurve)
		{
			Curve curve = CurveUtility.TransformCurveAtZAixs(input, useZ, true);
			double num = curve.GetEndParameter(0);
			double num2 = curve.GetEndParameter(1);
			useOutCurve = curve.Clone();
			XYZ xyz = curve.GetEndPoint(0);
			XYZ xyz2 = curve.GetEndPoint(1);
			BoundingBoxPakcer boundingBoxPakcer = new BoundingBoxPakcer(boundingBoxPacker.LstPoint[0], boundingBoxPacker.LstPoint[2], useZ, boundingBoxPacker.LstDriection);
			if (Utility.IfPointInRange(xyz, boundingBoxPakcer) && Utility.IfPointInRange(xyz2, boundingBoxPakcer))
			{
				return curve.Evaluate(0.5, true);
			}
			foreach (Line line in boundingBoxPakcer.LstBoundLine)
			{
				IntersectionResultArray intersectionResultArray;
				SetComparisonResult setComparisonResult = curve.Intersect(line, out intersectionResultArray);
				if (8 == (int)setComparisonResult)
				{
					XYZ xyzpoint = intersectionResultArray.get_Item(0).XYZPoint;
					if (!Utility.IfPointInRange(xyz, boundingBoxPakcer) && !Utility.IfPointInRange(xyz2, boundingBoxPakcer))
					{
						if (xyzpoint.DistanceTo(xyz) > xyzpoint.DistanceTo(xyz2))
						{
							xyz2 = xyzpoint;
							num2 = curve.Project(xyzpoint).Parameter;
						}
						else
						{
							xyz = xyzpoint;
							num = curve.Project(xyzpoint).Parameter;
						}
					}
					else if (!Utility.IfPointInRange(xyz, boundingBoxPakcer))
					{
						xyz = xyzpoint;
						num = curve.Project(xyzpoint).Parameter;
					}
					else if (!Utility.IfPointInRange(xyz2, boundingBoxPakcer))
					{
						xyz2 = xyzpoint;
						num2 = curve.Project(xyzpoint).Parameter;
					}
				}
			}
			useOutCurve.MakeUnbound();
			useOutCurve.MakeBound(Math.Min(num, num2), Math.Max(num, num2));
			return curve.Evaluate(0.5 * (num2 + num), false);
		}

		public static XYZ GetCurveMidPoint(Curve input, double useZ)
		{
			XYZ xyz = input.GetEndPoint(0).Add(input.GetEndPoint(1)).Divide(2.0);
			return new XYZ(xyz.X, xyz.Y, useZ);
		}

		public static double MMToFeet(double input, bool ifIsMMToFeet = true)
		{
			if (ifIsMMToFeet)
			{
				return input / 304.8;
			}
			return input * 304.8;
		}

		public static List<Line> GetALoopLine(List<XYZ> pointArrays)
		{
			List<Line> list = new List<Line>();
			for (int i = 0; i < pointArrays.Count; i++)
			{
				if (i != pointArrays.Count - 1)
				{
					list.Add(Line.CreateBound(pointArrays[i], pointArrays[i + 1]));
				}
				else
				{
					list.Add(Line.CreateBound(pointArrays[i], pointArrays[0]));
				}
			}
			return list;
		}

		public static bool IfLineInRange(Line inputLine, BoundingBoxPakcer boundingBoxPacker)
		{
			if (Utility.IfPointInRange(inputLine.GetEndPoint(0), boundingBoxPacker) || Utility.IfPointInRange(inputLine.GetEndPoint(1), boundingBoxPacker))
			{
				return true;
			}
			foreach (Line line in boundingBoxPacker.LstBoundLine)
			{
                if ((int)inputLine.Intersect(line) == 8)
				{
					return true;
				}
			}
			return false;
		}

		public static bool IfPointInRange(XYZ inputPoint, BoundingBoxPakcer boundingBoxPacker)
		{
			return boundingBoxPacker.IfPointInPacker(inputPoint);
		}

		public static XYZ PointAtUseZ(XYZ inputPoint, double useZ)
		{
			return new XYZ(inputPoint.X, inputPoint.Y, useZ);
		}

		public static XYZ IntersectionPoint(XYZ pointOne, XYZ pointTwo, XYZ driectionOne, XYZ driectionTwo)
		{
			Line line = Line.CreateUnbound(pointOne, driectionOne);
			line.MakeUnbound();
			Line line2 = Line.CreateUnbound(pointTwo, driectionTwo);
			line2.MakeUnbound();
			IntersectionResultArray intersectionResultArray;
			SetComparisonResult setComparisonResult = line.Intersect(line2, out intersectionResultArray);
			if (8 != (int)setComparisonResult)
			{
				return null;
			}
			return intersectionResultArray.get_Item(0).XYZPoint;
		}

		public static XYZ GetFamilyInstanceCentrePoint(FamilyInstance input)
		{
			GeometryElement transformed = input.GetOriginalGeometry(new Options
			{
                DetailLevel = (ViewDetailLevel)1
			}).GetTransformed(input.GetTransform());
			List<Solid> list = new List<Solid>();
			foreach (GeometryObject geometryObject in transformed)
			{
				if (geometryObject is Solid)
				{
					list.Add(geometryObject as Solid);
				}
			}
			list = (from k in list
			orderby -k.Volume
			select k).ToList<Solid>();
			return list[0].ComputeCentroid();
		}

		public static XYZ TransformPoint(XYZ point, Transform transform)
		{
			double x = point.X;
			double y = point.Y;
			double z = point.Z;
			XYZ xyz = transform.get_Basis(0);
			XYZ xyz2 = transform.get_Basis(1);
			XYZ xyz3 = transform.get_Basis(2);
			XYZ origin = transform.Origin;
			double num = x * xyz.X + y * xyz2.X + z * xyz3.X + origin.X;
			double num2 = x * xyz.Y + y * xyz2.Y + z * xyz3.Y + origin.Y;
			double num3 = x * xyz.Z + y * xyz2.Z + z * xyz3.Z + origin.Z;
			return new XYZ(num, num2, num3);
		}

		public static Curve CreateSameOffset(this Curve input, double offsetDist, XYZ normal)
		{
			Curve result;
			try
			{
				result = (input.GetType().InvokeMember(StaticResource.Str_CreateOffest, BindingFlags.InvokeMethod, null, input, new object[]
				{
					offsetDist,
					normal
				}) as Curve);
			}
			catch (Exception)
			{
				Transform transform = Transform.CreateTranslation(input.GetEndPoint(1).Add(-input.GetEndPoint(0)).Normalize().CrossProduct(normal).Normalize().Multiply(offsetDist));
				result = input.CreateTransformed(transform);
			}
			return result;
		}

		public static Curve CreateReversedUtility(this Curve input)
		{
			Curve result;
			try
			{
				result = (input.GetType().InvokeMember(StaticResource.Str_CreateReversed, BindingFlags.InvokeMethod, null, input, new object[0]) as Curve);
			}
			catch (Exception ex)
			{
				if (input is Line)
				{
					result = Line.CreateBound(input.GetEndPoint(1), input.GetEndPoint(0));
				}
				else
				{
					if (!(input is Arc))
					{
						throw ex;
					}
					XYZ center = (input as Arc).Center;
					result = Arc.Create(input.GetEndPoint(1), input.GetEndPoint(0), center);
				}
			}
			return result;
		}

		public static TextNoteType GetTextNoteType(Autodesk.Revit.DB.Document doc)
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(doc);
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(TextNoteType));
			filteredElementCollector.WherePasses(elementClassFilter);
			List<Element> list = (from e in filteredElementCollector
			where e.Name == "仿宋_3.5mm"
			select e).ToList<Element>();
			if (list.Count > 0)
			{
				return (TextNoteType)list.First<Element>();
			}
			TextNoteType textNoteType = (filteredElementCollector.First<Element>() as TextNoteType).Duplicate("仿宋_3.5mm") as TextNoteType;
			Parameter parameter = textNoteType.get_Parameter(BuiltInParameter.TEXT_FONT);
			if (parameter != null && !parameter.IsReadOnly)
			{
				parameter.Set("FangSong_GB2312");
			}
			parameter = textNoteType.get_Parameter(BuiltInParameter.TEXT_SIZE);
			if (parameter != null && !parameter.IsReadOnly)
			{
				parameter.Set(Utility.MMToFeet(3.5, true));
			}
			parameter = textNoteType.get_Parameter(BuiltInParameter.TEXT_WIDTH_SCALE);
			if (parameter != null && !parameter.IsReadOnly)
			{
				parameter.Set(0.7);
			}
			return textNoteType;
		}

		public static List<Curve> GetListTransformCurve(List<Curve> inputListCurve, Transform inputTransform)
		{
			List<Curve> list = new List<Curve>();
			if (inputTransform == null)
			{
				list.AddRange(inputListCurve);
			}
			else
			{
				foreach (Curve curve in inputListCurve)
				{
					list.Add(curve.CreateTransformed(inputTransform));
				}
			}
			return list;
		}
	}
}
